%==========================================================================
%=  This file is part of the Sound Restoration Project
%=  (c) Copyright Industrial Mathematics Institute
%=                University of South Carolina, Department of Mathematics
%=  ALL RIGHTS RESERVED
%=
%=  Author: Borislav Karaivanov
%==========================================================================

%==========================================================================
% List of the files on which this procedure depends:
%
% none
%
%==========================================================================

%==========================================================================
% The function "interpretInputArguments" interprets a list of a variable
% number of input arguments (the list is comprised of pairs of a parameter
% descriptor followed by a parameter value), and assigns the listed values
% to the appropriate output arguments.
% INPUT: "argInCellArr" is a list of a variable even number of input
% arguments.
% OUTPUT: "fingerprintMovieFileName" returns a string specifying the full
% path name of a movie file (in cineform .avi or .mov format) or a single
% image file (in .dpx format) storing the lighting fingerprint to be used
% for image calibration.
% "firstFileInd" and "lastFileInd" return (as integers) the indices of the
% first and the last images to be used.
% "indFieldLength" returns the number of digits to be used for indexing the
% consecutive images. Image indices are specified with leading zeros. For
% example, if the index field length is 6, then the index of image 241 will
% be specified as 000241 in its file name.
% "imageFileExt" returns a string specifying the common file extension of
% the image files from which sound is to be reconstructed.
% "numTestFiles" returns an integers specifying the number of image files
% to be drawn at random from the pool of all available image files and used
% directly for estimation of the sound track bounds.
% "leftBound" and "rightBound" return the left and right vertical bounds of 
% the sound track region in the given images.
% "numPerBatch" returns the number of image files to be processed in a
% batch and have the sound signals extracted from them written to the same
% text file.
% "soundTextFileName" returns a string specifying the name of a text file
% (including a full directory path) where all sound signals extracted from
% the uncalibrated images are stored.
% "imageCalibSoundTextFileName" returns a string specifying the name of a
% text file (including a full directory path) where all sound signals
% extracted from the calibrated images are stored.
% "numSmoothings" returns the number of smoothing passes to be applied to
% the raw averages of the sound signals.
% "movingAveSpan" returns the length of the stencil to be used for moving
% average smoothing of the average sound signal.
% "numSignalsPerMask" returns number of consecutive signals to be used in
% the construction of each sound-based calibration mask. 
% "degOfPolyFitArr" returns a vector holding degrees of polynomials to be
% fit to the average sound signal. The best fitting of these polynomials is
% to be sampled and used as a sound-based calibration mask.
% "maxAllowedCut" returns the maximal number of rows that one is allowed to
% discard from each image in order to compensate for uneven lighting or
% portion of the gate caught on the scans.
% "soundMovingAveSpan" returns the span to be used for the moving average
% smoothing of the extracted sound signal as a postprocessing step. Note
% that if value of zero is specified, then effectively the sound signal
% will not be smoothed at all.
% "numToUseForGuess" returns the number of pairs of consecutive signals
% whose overlaps are to be computed in order to produce an estimate for the
% most likely amount of overlap. These pairs are to be chosen randomly
% among all available pairs of consecutive signals.
% "locMinNbhdRad" returns the radius of the neighborhood (an interval, in
% fact, in 1D) around a point to be checked in order to claim a local
% minimum at that point. More precisely, we consider having a local minimum
% of the relative differences at a fixed overlap value if for all overlaps
% in the neighborhood of that value the relative differences are not
% smaller.
% "initSearchRad" returns the radius of an interval centered at the overlap
% guess where the initial search for the best-matching overlap is carried
% out. It is to reflect the belief of the calling function with respect to
% how far the best-matching overlaps are likely to be from the overlap
% guess.
% "maxHorizShift" returns the radius of an interval centered at zero where
% the initial search for the best-matching horizontal shift is carried out.
% It is to reflect the belief of the calling function with respect to how
% far away from zero the best-matching horizontal shifts are likely to be.
% "framesPerSecond" returns the desired speed (in frames per second) at
% which the sound signal is to be recorded.
% "maxAmplitude" returns the maximal amplitude that the sound signal should
% have before it is passed to the routine creating a .wav file. Keep in
% mind that that routine will clip all entries which fall outside the some
% interval ???? to be checked :[-1, 1).
% "bitsPerSample" returns the desired number of bits to be used in encoding
% each sample from the sound signal when it is stored as a .wav file.
% "doStruct" returns a structure whose fields are boolean flags indicating
% which steps of the algorithm are to be performed and which skipped by the
% particular function call.
% "isInputConsistent" is an optional output parameter which returns "false"
% if any inconsistency with input arguments is encountered (like unknown
% parameter description, or an odd number of input arguments), and "true"
% otherwise.
%==========================================================================
function [varStruct, doStruct] = interpretInputArguments(argInCellArr)

% Set default values.
varStruct.inFileName = '';
varStruct.imageDirPath = '';
varStruct.fingerprintMovieFileName = '';
varStruct.fingerprintImageFileName = '';
varStruct.fingerprintImageFileNamePrefix = '';
varStruct.firstFileInd = 0;
varStruct.lastFileInd = inf;
varStruct.indFieldLength = 6;
varStruct.imageFileExt = 'dpx';
varStruct.numTestFiles = 5;
varStruct.leftBound = [];
varStruct.rightBound = [];
varStruct.numPerBatch = 200;
varStruct.soundTextFileName = '';
varStruct.imageCalibSoundTextFileName = '';
varStruct.numSignalsPerMask = inf;
varStruct.numSmoothings = [];
varStruct.movingAveSpan = [];
varStruct.degOfPolyFitArr = (1:4);
varStruct.maxAllowedCut = 100;
varStruct.soundMovingAveSpan = 5;
varStruct.numToUseForGuess = 400;
varStruct.locMinNbhdRad = 5;
varStruct.initSearchRad = 10;
varStruct.maxHorizShift = 5;
varStruct.maxAmplitude = 0.4;
varStruct.framesPerSecond = 24;
varStruct.bitsPerSample = 16;
varStruct.audioDelay = 0;

% Assert that the input parameters are even number (for each descriptor
% there must be one value).
assert((mod(numel(argInCellArr), 2) == 0), ...
        'SoundRestoration:OddNumberOfInputs', ...
        'Odd number of input arguments specified. Can not be interpreted.');

% Check if any member of the structure of boolean flags is specified in the
% list of input arguments, and if so get the corresponding value from
% there.
try
    doStruct.doGenerateImageBasedCalibrationMask = ...
        getBooleanValue({'DoGenerateImageBasedCalibrationMask', 'doGenerateImageBasedCalibrationMask'}, argInCellArr);
    doStruct.doSoundTrackBounds = ...
        getBooleanValue({'DoSoundTrackBounds', 'doSoundTrackBounds'}, argInCellArr);
    doStruct.doExtractSoundSignals = ...
        getBooleanValue({'DoExtractSoundSignals', 'doExtractSoundSignals'}, argInCellArr);
    doStruct.doExtractSoundWithSoundOverlaps = ...
        getBooleanValue({'DoExtractSoundWithSoundOverlaps', 'doExtractSoundWithSoundOverlaps'}, argInCellArr);
    doStruct.doImproveSoundWithImageOverlaps = ...
        getBooleanValue({'DoImproveSoundWithImageOverlaps', 'doImproveSoundWithImageOverlaps'}, argInCellArr);
    doStruct.doExtractSoundWithImageCalibSoundOverlaps = ...
        getBooleanValue({'DoExtractSoundWithImageCalibSoundOverlaps', 'doExtractSoundWithImageCalibSoundOverlaps'}, argInCellArr);
    doStruct.doExtractSoundWithImageOverlaps = ...
        getBooleanValue({'DoExtractSoundWithImageOverlaps', 'doExtractSoundWithImageOverlaps'}, argInCellArr);
    doStruct.doExtractSoundWithImageCalibImageOverlaps = ...
        getBooleanValue({'DoExtractSoundWithImageCalibImageOverlaps', 'doExtractSoundWithImageCalibImageOverlaps'}, argInCellArr);
    doStruct.doSaveSound = ...
        getBooleanValue({'DoSaveSound', 'doSaveSound'}, argInCellArr);
    doStruct.doSyncAudioAndVideo = ...
        getBooleanValue({'DoSyncAudioAndVideo', 'doSyncAudioAndVideo'}, argInCellArr);


% Check if 'InFileName' is among the specified input arguments, and if so
% get the corresponding value from the list of input arguments. If the
% value is a single string specifying an existing file, then it is to be
% used to produce a sequence of image files.
[inFileName, testStr] = ...
    getMatchingValue({'InFileName', 'inFileName'}, argInCellArr);
if (isempty(inFileName) == false)
    % Assert that the given file name is a string.
    assert(ischar(inFileName), ...
        'SoundRestoration:interpretInputArguments:InFileNotString', ...
        ['The input argument immediately after %s is not a string.\n' ...
        'It needs to be a full path name specifying an existing Cineform movie of image file.'], testStr);
    % Assert that the input file exists.
    assert((exist(inFileName, 'file') == 2), ...
        'SoundRestoration:interpretInputArguments:InFileInexisting', ...
        ['The file %s can not be found.\n' ...
        'A full path name specifying an existing Cineform movie or image file is needed.'], inFileName);
    
    varStruct.inFileName = inFileName;
    % If the specified file is an image in pgm format, then change the
    % default image file format to pgm.
    if (strcmpi(inFileName((end - 3):end), '.pgm') == true)
        varStruct.imageFileExt = 'pgm';
    end
end


% Check if 'ImageDirectoryPath' is among the specified input arguments, and
% if so get the corresponding value from the list of input arguments. If
% the value is a single string specifying a non-existing directory path,
% then create all missing directory on that path.
[imageDirPath, testStr] = ...
    getMatchingValue({'ImageDirectoryPath', 'imageDirPath'}, argInCellArr);
if (isempty(imageDirPath) == false)
    % Assert that the given directory path is a string.
    assert(ischar(imageDirPath), ...
        'SoundRestoration:interpretInputArguments:ImageDirNotString', ...
        ['The input argument immediately after %s is not a string.\n' ...
        'It needs to be a full directory path.'], testStr);
    
    varStruct.imageDirPath = imageDirPath;
    % Create any missing directories on the specified directory path.
    if (exist(imageDirPath, 'dir') ~= 7)
        createMissingDirs(imageDirPath);
    end
end


% Check if 'LightingFingerprintMovieFileName' is among the specified input
% arguments, and if so get the corresponding value from the list of input
% arguments.
[fingerprintMovieFileName, testStr] = ...
    getMatchingValue({'LightingFingerprintMovieFileName', 'fingerprintMovieFileName'}, argInCellArr);
if (isempty(fingerprintMovieFileName) == false)
    % Assert that the given name of a lighting fingerprint movie file is a
    % string.
    assert(ischar(fingerprintMovieFileName), ...
        'SoundRestoration:interpretInputArguments:FingerprintMovieNotString', ...
        ['The input argument immediately after %s is not a string.\n' ...
        'It needs to be a full path name specifying an existing file.'], testStr);
    % Assert that the lighting fingerprint movie file exists.
    assert((exist(fingerprintMovieFileName, 'file') == 2), ...
        'SoundRestoration:interpretInputArguments:FingerprintMovieInexisting', ...
        ['The file %s can not be found.\n' ...
        'A full path name specifying an existing file is needed.'], fingerprintMovieFileName);
    
    varStruct.fingerprintMovieFileName = fingerprintMovieFileName;
end


% Check if 'LightingFingerprintImageFileName' is among the specified input
% arguments, and if so get the corresponding value from the list of input
% arguments.
[fingerprintImageFileName, testStr] = ...
    getMatchingValue({'LightingFingerprintImageFileName', 'fingerprintImageFileName'}, argInCellArr);
if (isempty(fingerprintImageFileName) == false)
    % Assert that the given name of a lighting fingerprint image file is a
    % string.
    assert(ischar(fingerprintImageFileName), ...
        'SoundRestoration:interpretInputArguments:FingerprintImageNotString', ...
        ['The input argument immediately after %s is not a string.\n' ...
        'It needs to be a full path name specifying an existing file.'], testStr);
    % Assert that the lighting fingerprint image file exists.
    assert((exist(fingerprintImageFileName, 'file') == 2), ...
        'SoundRestoration:interpretInputArguments:FingerprintImageInexisting', ...
        ['The file %s can not be found.\n' ...
        'A full path name specifying an existing file is needed.'], fingerprintImageFileName);
    
    varStruct.fingerprintImageFileName = fingerprintImageFileName;
end


% Check if 'LightingFingerprintImageFileNamePrefix' is among the specified
% input arguments, and if so get the corresponding value from the list of
% input arguments.
[fingerprintImageFileNamePrefix, testStr] = ...
    getMatchingValue({'LightingFingerprintImageFileNamePrefix', 'fingerprintImageFileNamePrefix'}, argInCellArr);
if (isempty(fingerprintImageFileNamePrefix) == false)
    % Assert that the given lighting fingerprint image file name prefix is
    % a string.
    assert(ischar(fingerprintImageFileNamePrefix), ...
        'SoundRestoration:interpretInputArguments:FingerprintPrefixNotString', ...
        ['The input argument immediately after %s is not a string.\n' ...
        'It needs to be a full path prefix of an existing file.'], testStr);
    
    varStruct.fingerprintImageFileNamePrefix = fingerprintImageFileNamePrefix;
end

% If a lighting fingerprint information is not specified in any way, then
% image-based calibration would not be possible.
if ( (isempty(varStruct.fingerprintMovieFileName) == true)&& ...
        (isempty(varStruct.fingerprintImageFileName) == true)&& ...
        (isempty(varStruct.fingerprintImageFileNamePrefix) == true) )
    
    doStruct.doGenerateImageBasedCalibrationMask = false;
    doStruct.doExtractSoundWithImageCalibSoundOverlaps = false;
    doStruct.doExtractSoundWithImageCalibImageOverlaps = false;
end


% Check if 'FirstFileIndex' is among the specified input arguments, and if
% so get the corresponding value from the list of input arguments.
[firstFileInd, testStr] = getMatchingValue({'FirstFileIndex', 'firstFileInd'}, argInCellArr);
if (isempty(firstFileInd) == false)
    % Assert that the given index is a number.
    assert(isnumeric(firstFileInd), ...
        'SoundRestoration:interpretInputArguments:FirstFileIndNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given index is a real number.
    assert(isreal(firstFileInd), ...
        'SoundRestoration:interpretInputArguments:FirstFileIndNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given index is a scalar (i.e., not an array).
    assert(isscalar(firstFileInd), ...
        'SoundRestoration:interpretInputArguments:FirstFileIndNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given index is an integer.
    assert((firstFileInd == floor(firstFileInd)), ...
        'SoundRestoration:interpretInputArguments:FirstFileIndNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given index is non-negative.
    assert((firstFileInd >= 0), ...
        'SoundRestoration:interpretInputArguments:FirstFileIndNegative', ...
        ['The input argument immediately after %s is negative.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    
    varStruct.firstFileInd = firstFileInd;
end


% Check if 'LastFileIndex' is among the specified input arguments, and if
% so get the corresponding value from the list of input arguments.
[lastFileInd, testStr] = getMatchingValue({'LastFileIndex', 'lastFileInd'}, argInCellArr);
if (isempty(lastFileInd) == false)
    % Assert that the given index is a number.
    assert(isnumeric(lastFileInd), ...
        'SoundRestoration:interpretInputArguments:LastFileIndNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given index is a real number.
    assert(isreal(lastFileInd), ...
        'SoundRestoration:interpretInputArguments:LastFileIndNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given index is a scalar (i.e., not an array).
    assert(isscalar(lastFileInd), ...
        'SoundRestoration:interpretInputArguments:LastFileIndNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given index is an integer.
    assert((lastFileInd == floor(lastFileInd)), ...
        'SoundRestoration:interpretInputArguments:LastFileIndNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given index is non-negative.
    assert((lastFileInd >= 0), ...
        'SoundRestoration:interpretInputArguments:LastFileIndNegative', ...
        ['The input argument immediately after %s is negative.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    
    varStruct.lastFileInd = lastFileInd;
end


% Assert that the first image index is not greater than the last image
% index.
assert((varStruct.firstFileInd <= varStruct.lastFileInd), ...
    'SoundRestoration:interpretInputArguments:FileIndRangeEmpty', ...
    'The index of the first image is greater than the index of the last.');


% Check if 'IndexFieldLength' is among the specified input arguments, and
% if so get the corresponding value from the list of input arguments.
[indFieldLength, testStr] = getMatchingValue({'IndexFieldLength', 'indFieldLength'}, argInCellArr);
if (isempty(indFieldLength) == false)
    % Assert that the given index field length is a number.
    assert(isnumeric(indFieldLength), ...
        'SoundRestoration:interpretInputArguments:IndLenNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single integer between 1 and 10.\n' ...
        'Value of 6 seems sufficient for all practical purposes.'], testStr);
    % Assert that the given index field length is a real number.
    assert(isreal(indFieldLength), ...
        'SoundRestoration:interpretInputArguments:IndLenNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single integer between 1 and 10.\n' ...
        'Value of 6 seems sufficient for all practical purposes.'], testStr);
    % Assert that the given index field length is a scalar.
    assert(isscalar(indFieldLength), ...
        'SoundRestoration:interpretInputArguments:IndLenNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single integer between 1 and 10.\n' ...
        'Value of 6 seems sufficient for all practical purposes.'], testStr);
    % Assert that the given index field length is an integer.
    assert((indFieldLength == floor(indFieldLength)), ...
        'SoundRestoration:interpretInputArguments:IndLenNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single integer between 1 and 10.\n' ...
        'Value of 6 seems sufficient for all practical purposes.'], testStr);
    % Assert that the given index field length is at least 1.
    assert((indFieldLength >= 1), ...
        'SoundRestoration:interpretInputArguments:IndLenLessThan1', ...
        ['The index field length is smaller than 1.\n' ...
        'It needs to be a single integer between 1 and 10.\n' ...
        'Value of 6 seems sufficient for all practical purposes.']);
    % Assert that the given index field length is at most 10.
    assert((indFieldLength <= 10), ...
        'SoundRestoration:interpretInputArguments:IndLenGreaterThan10', ...
        ['The index field length is greater than 10.\n' ...
        'It needs to be a single integer between 1 and 10.\n' ...
        'Value of 6 seems sufficient for all practical purposes.']);
    
    varStruct.indFieldLength = indFieldLength;
end


% Check if 'ImageFileExtension' is among the specified input arguments, and
% if so get the corresponding value from the list of input arguments.
[imageFileExt, testStr] = getMatchingValue({'ImageFileExtension', 'imageFileExt'}, argInCellArr);
if (isempty(imageFileExt) == false)
    % Assert that the given image files extension is a string.
    assert(ischar(imageFileExt), ...
        'SoundRestoration:interpretInputArguments:ImageFileExtNotString', ...
        ['The input argument immediately after %s is not a string.\n' ...
        'Only the string ''dpx'' or ''pgm'' (case insensitive) would be an acceptable value.'], testStr);
    % Assert that the given image files extension is either 'dpx' or 'pgm'.
    assert(((strcmpi(imageFileExt, 'dpx') == true)||(strcmpi(imageFileExt, 'pgm') == true)), ...
        'SoundRestoration:interpretInputArguments:ImageFileExtNotAllowed', ...
        ['The image file extension %s is not allowed.\n' ...
        'Only the string ''dpx'' or ''pgm'' (case insensitive) would be accepted.'], imageFileExt);
    
    varStruct.imageFileExt = imageFileExt;
end


% Check if 'NumberOfSoundTrackBoundsTestFiles' is among the specified input
% arguments, and if so get the corresponding value from the list of input
% arguments.
[numTestFiles, testStr] = getMatchingValue({'NumberOfSoundTrackBoundsTestFiles', 'numTestFiles'}, argInCellArr);
if (isempty(numTestFiles) == false)
    % Assert that the given number of test files is a number.
    assert(isnumeric(numTestFiles), ...
        'SoundRestoration:interpretInputArguments:NumTestFilesNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, positive integer.\n' ...
        'Value of 5 seems sufficient for all practical purposes.'], testStr);
    % Assert that the given number of test files is a real number.
    assert(isreal(numTestFiles), ...
        'SoundRestoration:interpretInputArguments:NumTestFilesNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, positive integer.\n' ...
        'Value of 5 seems sufficient for all practical purposes.'], testStr);
    % Assert that the given number of test files is a scalar.
    assert(isscalar(numTestFiles), ...
        'SoundRestoration:interpretInputArguments:NumTestFilesNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, positive integer.\n' ...
        'Value of 5 seems sufficient for all practical purposes.'], testStr);
    % Assert that the given number of test files is an integer.
    assert((numTestFiles == floor(numTestFiles)), ...
        'SoundRestoration:interpretInputArguments:NumTestFilesNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, positive integer.\n' ...
        'Value of 5 seems sufficient for all practical purposes.'], testStr);
    % Assert that the given number of test files is at least 1.
    assert((numTestFiles >= 1), ...
        'SoundRestoration:interpretInputArguments:NumTestFilesLessThan1', ...
        ['The number of test files is smaller than 1.\n' ...
        'It needs to be a single, positive integer.\n' ...
        'Value of 5 seems sufficient for all practical purposes.']);
    
    varStruct.numTestFiles = numTestFiles;
end


% Check if 'LeftSoundTrackBound' is among the specified input arguments,
% and if so get the corresponding value from the list of input arguments.
[leftBound, testStr] = getMatchingValue({'LeftSoundTrackBound', 'leftBound'}, argInCellArr);
if (isempty(leftBound) == false)
    % Assert that the given left bound is a number.
    assert(isnumeric(leftBound), ...
        'SoundRestoration:interpretInputArguments:LeftBoundNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given left bound is a real number.
    assert(isreal(leftBound), ...
        'SoundRestoration:interpretInputArguments:LeftBoundNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given left bound is a scalar.
    assert(isscalar(leftBound), ...
        'SoundRestoration:interpretInputArguments:LeftBoundNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given left bound is an integer.
    assert((leftBound == floor(leftBound)), ...
        'SoundRestoration:interpretInputArguments:LeftBoundNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given left bound is at least 1.
    assert((leftBound >= 1), ...
        'SoundRestoration:interpretInputArguments:LeftBoundLessThan1', ...
        ['The left bound is smaller than 1.\n' ...
        'It needs to be a single, positive integer.']);
    
    varStruct.leftBound = leftBound;
end


% Check if 'RightSoundTrackBound' is among the specified input arguments,
% and if so get the corresponding value from the list of input arguments.
[rightBound, testStr] = getMatchingValue({'RightSoundTrackBound', 'rightBound'}, argInCellArr);
if (isempty(rightBound) == false)
    % Assert that the given right bound is a number.
    assert(isnumeric(rightBound), ...
        'SoundRestoration:interpretInputArguments:RightBoundNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given right bound is a real number.
    assert(isreal(rightBound), ...
        'SoundRestoration:interpretInputArguments:RightBoundNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given right bound is a scalar.
    assert(isscalar(rightBound), ...
        'SoundRestoration:interpretInputArguments:RightBoundNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given right bound is an integer.
    assert((rightBound == floor(rightBound)), ...
        'SoundRestoration:interpretInputArguments:RightBoundNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given right bound is at least 1.
    assert((rightBound >= 1), ...
        'SoundRestoration:interpretInputArguments:RightBoundLessThan1', ...
        ['The right bound is smaller than 1.\n' ...
        'It needs to be a single, positive integer.']);
    
    varStruct.rightBound = rightBound;
end

% If both the left and the right sound track bounds are specified, then the
% step for finding them can be skipped.
if ( (isempty(varStruct.leftBound) == false)&&(isempty(varStruct.rightBound) == false) )
    doStruct.doSoundTrackBounds = false;
end


% Check if 'NumberOfSoundSignalsPerBatch' is among the specified input
% arguments, and if so get the corresponding value from the list of input
% arguments.
[numPerBatch, testStr] = getMatchingValue({'NumberOfSoundSignalsPerBatch', 'numPerBatch'}, argInCellArr);
if (isempty(numPerBatch) == false)
    % Assert that the given number of files per batch is a number.
    assert(isnumeric(numPerBatch), ...
        'SoundRestoration:interpretInputArguments:NumPerBatchNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given number of files per batch is a real number.
    assert(isreal(numPerBatch), ...
        'SoundRestoration:interpretInputArguments:NumPerBatchNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given number of files per batch is a scalar.
    assert(isscalar(numPerBatch), ...
        'SoundRestoration:interpretInputArguments:NumPerBatchNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given number of files per batch is an integer.
    assert((numPerBatch == floor(numPerBatch)), ...
        'SoundRestoration:interpretInputArguments:NumPerBatchNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given number of files per batch is at least 1.
    assert((numPerBatch >= 1), ...
        'SoundRestoration:interpretInputArguments:NumPerBatchLessThan1', ...
        ['The number of files per batch is smaller than 1.\n' ...
        'It needs to be a single, positive integer.']);
    
    varStruct.numPerBatch = numPerBatch;
end


% Check if 'SoundTextFileName' is among the specified input arguments, and
% if so get the corresponding value from the list of input arguments. If
% the value is a single string specifying the name of an existing text
% file, then there is no need to do sound extraction.
[soundTextFileName, testStr] = getMatchingValue({'SoundTextFileName', 'soundTextFileName'}, argInCellArr);
if (isempty(soundTextFileName) == false)
    % Assert that the given sound text file name is a string.
    assert(ischar(soundTextFileName), ...
        'SoundRestoration:interpretInputArguments:SoundTextFileNotString', ...
        ['The input argument immediately after %s is not a string.\n' ...
        'A full path name specifying an existing text file is needed.'], testStr);
    % Assert that the sound text file exists.
    assert((exist(soundTextFileName, 'file') == 2), ...
        'SoundRestoration:interpretInputArguments:SoundTextFileInexisting', ...
        ['The file %s can not be found.\n' ...
        'A full path name specifying an existing text file is needed.'], inFileName);
    
    varStruct.soundTextFileName = soundTextFileName;
    doStruct.doExtractSoundSignals = false;
end


% Check if 'ImageCalibSoundTextFileName' is among the specified input
% arguments, and if so get the corresponding value from the list of input
% arguments. If the value is a single string specifying the name of an
% existing text file, then there is no need to do sound extraction.
[imageCalibSoundTextFileName, testStr] = getMatchingValue({'ImageCalibSoundTextFileName', 'imageCalibSoundTextFileName'}, argInCellArr);
if (isempty(imageCalibSoundTextFileName) == false)
    % Assert that the given image calibration sound text file name is a
    % string.
    assert(ischar(imageCalibSoundTextFileName), ...
        'SoundRestoration:interpretInputArguments:ImageCalibSoundTextNotString', ...
        ['The input argument immediately after %s is not a string.\n' ...
        'A full path name specifying an existing text file is needed.'], testStr);
    % Assert that the image calibration sound text file exists.
    assert((exist(imageCalibSoundTextFileName, 'file') == 2), ...
        'SoundRestoration:interpretInputArguments:ImageCalibSoundTextInexisting', ...
        ['The file %s can not be found.\n' ...
        'A full path name specifying an existing text file is needed.'], imageCalibSoundTextFileName);
    
    varStruct.imageCalibSoundTextFileName = imageCalibSoundTextFileName;
    doStruct.doExtractSoundSignals = false;
end


% Check if 'NumberOfSoundSignalsPerMask' is among the specified input
% arguments, and if so get the corresponding value from the list of input
% arguments.
[numSignalsPerMask, testStr] = getMatchingValue({'NumberOfSoundSignalsPerMask', 'numSignalsPerMask'}, argInCellArr);
if (isempty(numSignalsPerMask) == false)
    % Assert that the given number of signals per mask is a number.
    assert(isnumeric(numSignalsPerMask), ...
        'SoundRestoration:interpretInputArguments:NumSignalsPerMaskNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given number of signals per mask is a real number.
    assert(isreal(numSignalsPerMask), ...
        'SoundRestoration:interpretInputArguments:NumSignalsPerMaskNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given number of signals per mask is a scalar.
    assert(isscalar(numSignalsPerMask), ...
        'SoundRestoration:interpretInputArguments:NumSignalsPerMaskNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given number of signals per mask is an integer.
    assert((numSignalsPerMask == floor(numSignalsPerMask)), ...
        'SoundRestoration:interpretInputArguments:NumSignalsPerMaskNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given number of signals per mask is at least 1.
    assert((numSignalsPerMask >= 1), ...
        'SoundRestoration:interpretInputArguments:NumSignalsPerMaskLessThan1', ...
        ['The number of signals per mask is smaller than 1.\n' ...
        'It needs to be a single, positive integer.']);
    
    varStruct.numSignalsPerMask = numSignalsPerMask;
end


% Check if 'NumberOfSmoothingPasses' is among the specified input
% arguments, and if so get the corresponding value from the list of input
% arguments.
[numSmoothings, testStr] = getMatchingValue({'NumberOfSmoothingPasses', 'numSmoothings'}, argInCellArr);
if (isempty(numSmoothings) == false)
    % Assert that the given number of smoothings is a number.
    assert(isnumeric(numSmoothings), ...
        'SoundRestoration:interpretInputArguments:NumSmoothingsNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given number of smoothings is a real number.
    assert(isreal(numSmoothings), ...
        'SoundRestoration:interpretInputArguments:NumSmoothingsNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given number of smoothings is a scalar.
    assert(isscalar(numSmoothings), ...
        'SoundRestoration:interpretInputArguments:NumSmoothingsNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given number of smoothings is an integer.
    assert((numSmoothings == floor(numSmoothings)), ...
        'SoundRestoration:interpretInputArguments:NumSmoothingsNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given number of smoothings is at least 1.
    assert((numSmoothings >= 0), ...
        'SoundRestoration:interpretInputArguments:NumSmoothingsNegative', ...
        ['The number of smoothings is negative.\n' ...
        'It needs to be a single, non-negative integer.']);
    
    varStruct.numSmoothings = numSmoothings;
end


% Check if 'MovingAverageStencilSpan' is among the specified input
% arguments, and if so get the corresponding value from the list of input
% arguments.
[movingAveSpan, testStr] = getMatchingValue({'MovingAverageStencilSpan', 'movingAveSpan'}, argInCellArr);
if (isempty(movingAveSpan) == false)
    % Assert that the given moving average span is a number.
    assert(isnumeric(movingAveSpan), ...
        'SoundRestoration:interpretInputArguments:MovingAveSpanNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given moving average span is a real number.
    assert(isreal(movingAveSpan), ...
        'SoundRestoration:interpretInputArguments:MovingAveSpanNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given moving average span is a scalar.
    assert(isscalar(movingAveSpan), ...
        'SoundRestoration:interpretInputArguments:MovingAveSpanNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given moving average span is an integer.
    assert((movingAveSpan == floor(movingAveSpan)), ...
        'SoundRestoration:interpretInputArguments:MovingAveSpanNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given moving average span is at least 1.
    assert((movingAveSpan >= 1), ...
        'SoundRestoration:interpretInputArguments:MovingAveSpanLessThan1', ...
        ['The moving average span is smaller than 1.\n' ...
        'It needs to be a single, positive integer.']);
    
    varStruct.movingAveSpan = movingAveSpan;
end


% Check if 'DegreeOfPolynomialFit' is among the specified input arguments,
% and if so get the corresponding value from the list of input arguments.
[degOfPolyFitArr, testStr] = getMatchingValue({'DegreesOfPolynomialFit', 'degOfPolyFitArr'}, argInCellArr);
if (isempty(degOfPolyFitArr) == false)
    % Assert that the given degrees of polynomial fit are numbers.
    assert(isnumeric(degOfPolyFitArr), ...
        'SoundRestoration:interpretInputArguments:DegOfPolyFitNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be an array of small positive integers.'], testStr);
    % Assert that the given degrees of polynomial fit are real numbers.
    assert(isreal(degOfPolyFitArr), ...
        'SoundRestoration:interpretInputArguments:DegOfPolyFitNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be an array of small positive integers.'], testStr);
    % Assert that the given degrees of polynomial fit are integers.
    assert(~any(degOfPolyFitArr ~= floor(degOfPolyFitArr)), ...
        'SoundRestoration:interpretInputArguments:DegOfPolyFitNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be an array of small positive integers.'], testStr);
    % Assert that the given degrees of polynomial fit are at least 1.
    assert(~any(degOfPolyFitArr < 1), ...
        'SoundRestoration:interpretInputArguments:DegOfPolyFitLessThan1', ...
        ['At least one of the degrees of polynomial fit is smaller than 1.\n' ...
        'They need to be small positive integers.']);
    
    varStruct.degOfPolyFitArr = degOfPolyFitArr;
    varStruct.numSmoothings = [];
    varStruct.movingAveSpan = [];
else
    % Keep the default value only if a value for at least one of the
    % variables "numSmoothings" and "movingAveSpan" has not been specified.
    if ( (isempty(varStruct.movingAveSpan) == false)&&(isempty(numSmoothings) == false) )
        varStruct.degOfPolyFitArr = [];
    else
        varStruct.numSmoothings = [];
        varStruct.movingAveSpan = [];
    end
end


% Check if 'MaxAllowedCut' is among the specified input arguments, and if
% so get the corresponding value from the list of input arguments.
[maxAllowedCut, testStr] = getMatchingValue({'MaxAllowedCut', 'maxAllowedCut'}, argInCellArr);
if (isempty(maxAllowedCut) == false)
    % Assert that the maximal allowed number of rows to discard is a
    % number.
    assert(isnumeric(maxAllowedCut), ...
        'SoundRestoration:interpretInputArguments:MaxAllowedCut', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the maximal allowed number of rows to discard is a real
    % number.
    assert(isreal(maxAllowedCut), ...
        'SoundRestoration:interpretInputArguments:MaxAllowedCut', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the maximal allowed number of rows to discard is a
    % scalar.
    assert(isscalar(maxAllowedCut), ...
        'SoundRestoration:interpretInputArguments:MaxAllowedCut', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the maximal allowed number of rows to discard is an
    % integer.
    assert((maxAllowedCut == floor(maxAllowedCut)), ...
        'SoundRestoration:interpretInputArguments:MaxAllowedCut', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    
    varStruct.maxAllowedCut = maxAllowedCut;
end


% Check if 'SoundMovingAveSpan' is among the specified input arguments, and
% if so get the corresponding value from the list of input arguments.
[soundMovingAveSpan, testStr] = getMatchingValue({'SoundMovingAveSpan', 'soundMovingAveSpan'}, argInCellArr);
if (isempty(soundMovingAveSpan) == false)
    % Assert that the span of the moving average smoothing is a number.
    assert(isnumeric(soundMovingAveSpan), ...
        'SoundRestoration:interpretInputArguments:SoundMovingAveSpan', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the span of the moving average smoothing is a real
    % number.
    assert(isreal(soundMovingAveSpan), ...
        'SoundRestoration:interpretInputArguments:SoundMovingAveSpan', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the span of the moving average smoothing is a scalar.
    assert(isscalar(soundMovingAveSpan), ...
        'SoundRestoration:interpretInputArguments:SoundMovingAveSpan', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the span of the moving average smoothing is an integer.
    assert((soundMovingAveSpan == floor(soundMovingAveSpan)), ...
        'SoundRestoration:interpretInputArguments:SoundMovingAveSpan', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the span of the moving average smoothing is non-negative.
    assert((soundMovingAveSpan >= 0), ...
        'SoundRestoration:interpretInputArguments:SoundMovingAveSpan', ...
        ['The span of the moving average smoothing is negative.\n' ...
        'It needs to be a single, non-negative integer.']);
    
    varStruct.soundMovingAveSpan = soundMovingAveSpan;
end


% Check if 'NumberOfSignalsToUseForGuessingOverlap' is among the specified
% input arguments, and if so get the corresponding value from the list of
% input arguments.
[numToUseForGuess, testStr] = getMatchingValue({'NumberOfSignalsToUseForGuessingOverlap', 'numToUseForGuess'}, argInCellArr);
if (isempty(numToUseForGuess) == false)
    % Assert that the given number of signals to use for guessing is a
    % number.
    assert(isnumeric(numToUseForGuess), ...
        'SoundRestoration:interpretInputArguments:NumToUseForGuessNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the given number of signals to use for guessing is a real
    % number.
    assert(isreal(numToUseForGuess), ...
        'SoundRestoration:interpretInputArguments:NumToUseForGuessNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the given number of signals to use for guessing is a
    % scalar.
    assert(isscalar(numToUseForGuess), ...
        'SoundRestoration:interpretInputArguments:NumToUseForGuessNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the given number of signals to use for guessing is an
    % integer.
    assert((numToUseForGuess == floor(numToUseForGuess)), ...
        'SoundRestoration:interpretInputArguments:NumToUseForGuessNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, (large) positive integer.'], testStr);
    % Assert that the given number of signals to use for guessing is at
    % least 1.
    assert((numToUseForGuess >= 1), ...
        'SoundRestoration:interpretInputArguments:NumToUseForGuessLessThan1', ...
        ['The number of signals to use for guessing is smaller than 1.\n' ...
        'It needs to be a single, (large) positive integer.']);
    
    varStruct.numToUseForGuess = numToUseForGuess;
end


% Check if 'LocalMinNbhdRadius' is among the specified input arguments, and
% if so get the corresponding value from the list of input arguments.
[locMinNbhdRad, testStr] = getMatchingValue({'LocalMinNbhdRadius', 'locMinNbhdRad'}, argInCellArr);
if (isempty(locMinNbhdRad) == false)
    % Assert that the given local min neighborhood radius is a number.
    assert(isnumeric(locMinNbhdRad), ...
        'SoundRestoration:interpretInputArguments:LocMinNbhdRadNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given local min neighborhood radius is a real number.
    assert(isreal(locMinNbhdRad), ...
        'SoundRestoration:interpretInputArguments:LocMinNbhdRadNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given local min neighborhood radius is a scalar.
    assert(isscalar(locMinNbhdRad), ...
        'SoundRestoration:interpretInputArguments:LocMinNbhdRadNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given local min neighborhood radius is an integer.
    assert((locMinNbhdRad == floor(locMinNbhdRad)), ...
        'SoundRestoration:interpretInputArguments:LocMinNbhdRadNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given local min neighborhood radius is at least 1.
    assert((locMinNbhdRad >= 1), ...
        'SoundRestoration:interpretInputArguments:LocMinNbhdRadLessThan1', ...
        ['The local min neighborhood radius is smaller than 1.\n' ...
        'It needs to be a single, positive integer.']);
    
    varStruct.locMinNbhdRad = locMinNbhdRad;
end


% Check if 'InitialSearchRadius' is among the specified input arguments,
% and if so get the corresponding value from the list of input arguments.
[initSearchRad, testStr] = getMatchingValue({'InitialSearchRadius', 'initSearchRad'}, argInCellArr);
if (isempty(initSearchRad) == false)
    % Assert that the given initial search radius is a number.
    assert(isnumeric(initSearchRad), ...
        'SoundRestoration:interpretInputArguments:InitSearchRadNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given initial search radius is a real number.
    assert(isreal(initSearchRad), ...
        'SoundRestoration:interpretInputArguments:InitSearchRadNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given initial search radius is a scalar.
    assert(isscalar(initSearchRad), ...
        'SoundRestoration:interpretInputArguments:InitSearchRadNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given initial search radius is an integer.
    assert((initSearchRad == floor(initSearchRad)), ...
        'SoundRestoration:interpretInputArguments:InitSearchRadNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, positive integer.'], testStr);
    % Assert that the given initial search radius is at least 1.
    assert((initSearchRad >= 1), ...
        'SoundRestoration:interpretInputArguments:InitSearchRadLessThan1', ...
        ['The initial search radius is smaller than 1.\n' ...
        'It needs to be a single, positive integer.']);
    
    varStruct.initSearchRad = initSearchRad;
end


% Check if 'MaxHorizontalShift' is among the specified input arguments, and
% if so get the corresponding value from the list of input arguments.
[maxHorizShift, testStr] = getMatchingValue({'MaxHorizontalShift', 'maxHorizShift'}, argInCellArr);
if (isempty(maxHorizShift) == false)
    % Assert that the given maximal horizontal shift is a number.
    assert(isnumeric(maxHorizShift), ...
        'SoundRestoration:interpretInputArguments:MaxHorizShiftNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given maximal horizontal shift is a real number.
    assert(isreal(maxHorizShift), ...
        'SoundRestoration:interpretInputArguments:MaxHorizShiftNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given maximal horizontal shift is a scalar.
    assert(isscalar(maxHorizShift), ...
        'SoundRestoration:interpretInputArguments:MaxHorizShiftNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given maximal horizontal shift is an integer.
    assert((maxHorizShift == floor(maxHorizShift)), ...
        'SoundRestoration:interpretInputArguments:MaxHorizShiftNotInteger', ...
        ['The input argument immediately after %s is not an integer.\n' ...
        'It needs to be a single, non-negative integer.'], testStr);
    % Assert that the given maximal horizontal shift is non-negative.
    assert((maxHorizShift >= 0), ...
        'SoundRestoration:interpretInputArguments:MaxHorizShiftNegative', ...
        ['The maximal horizontal shift is negative.\n' ...
        'It needs to be a single, non-negative integer.']);
    
    varStruct.maxHorizShift = maxHorizShift;
end


% Check if 'MaxAmplitude' is among the specified input arguments, and if
% so get the corresponding value from the list of input arguments.
[maxAmplitude, testStr] = getMatchingValue({'MaxAmplitude', 'maxAmplitude'}, argInCellArr);
if (isempty(maxAmplitude) == false)
    % Assert that the given maximal amplitude is a number.
    assert(isnumeric(maxAmplitude), ...
        'SoundRestoration:interpretInputArguments:MaxAmplitudeNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, positive real number.'], testStr);
    % Assert that the given maximal amplitude is a real number.
    assert(isreal(maxAmplitude), ...
        'SoundRestoration:interpretInputArguments:MaxAmplitudeNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, positive real number.'], testStr);
    % Assert that the given maximal amplitude is a scalar.
    assert(isscalar(maxAmplitude), ...
        'SoundRestoration:interpretInputArguments:MaxAmplitudeNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, positive real number.'], testStr);
    % Assert that the given maximal amplitude is positive.
    assert((maxAmplitude > 0), ...
        'SoundRestoration:interpretInputArguments:MaxAmplitudeNotPositive', ...
        ['The maximal amplitude is not positive.\n' ...
        'It needs to be a single, positive real number.']);
    
    varStruct.maxAmplitude = maxAmplitude;
end


% Check if 'FramesPerSecond' is among the specified input arguments, and if
% so get the corresponding value from the list of input arguments.
[framesPerSecond, testStr] = getMatchingValue({'FramesPerSecond', 'framesPerSecond'}, argInCellArr);
if (isempty(framesPerSecond) == false)
    % Assert that the given frame rate is a number.
    assert(isnumeric(framesPerSecond), ...
        'SoundRestoration:interpretInputArguments:FramesPerSecondNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single, positive real number.'], testStr);
    % Assert that the given frame rate is a real number.
    assert(isreal(framesPerSecond), ...
        'SoundRestoration:interpretInputArguments:FramesPerSecondNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single, positive real number.'], testStr);
    % Assert that the given frame rate is a scalar.
    assert(isscalar(framesPerSecond), ...
        'SoundRestoration:interpretInputArguments:FramesPerSecondNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single, positive real number.'], testStr);
    % Assert that the given frame rate is positive.
    assert((framesPerSecond > 0), ...
        'SoundRestoration:interpretInputArguments:FramesPerSecondNotPositive', ...
        ['The frame rate is not positive.\n' ...
        'It needs to be a single, positive real number.']);
    
    varStruct.framesPerSecond = framesPerSecond;
end


% Check if 'BitsPerSample' is among the specified input arguments, and if
% so get the corresponding value from the list of input arguments.
allowedBitsPerSampleArr = [8, 16, 24, 32];
[bitsPerSample, testStr] = getMatchingValue({'BitsPerSample', 'bitsPerSample'}, argInCellArr);
if (isempty(bitsPerSample) == false)
    % Assert that the given bit rate is among the allowed numbers.
    assert(ismember(bitsPerSample, allowedBitsPerSampleArr), ...
        'SoundRestoration:interpretInputArguments:BitRateNotAllowed', ...
        ['The input argument immediately after %s is not among the allowed bit rates.\n' ...
        'The only acceptable values are: %s.'], testStr, num2str(allowedBitsPerSampleArr));
    
    varStruct.bitsPerSample = bitsPerSample;
end


% Check if 'AudioDelay' is among the specified input arguments, and if so
% get the corresponding value from the list of input arguments.
[audioDelay, testStr] = getMatchingValue({'AudioDelay', 'audioDelay'}, argInCellArr);
if (isempty(audioDelay) == false)
    % Assert that the given audio delay is a number.
    assert(isnumeric(audioDelay), ...
        'SoundRestoration:interpretInputArguments:AudioDelayNotNumber', ...
        ['The input argument immediately after %s is not a number.\n' ...
        'It needs to be a single real number.'], testStr);
    % Assert that the given audio delay is a real number.
    assert(isreal(audioDelay), ...
        'SoundRestoration:interpretInputArguments:AudioDelayNotRealNumber', ...
        ['The input argument immediately after %s is not a real number.\n' ...
        'It needs to be a single real number.'], testStr);
    % Assert that the given audio delay is a scalar.
    assert(isscalar(audioDelay), ...
        'SoundRestoration:interpretInputArguments:AudioDelayNotScalar', ...
        ['The input argument immediately after %s is not a scalar.\n' ...
        'It needs to be a single real number.'], testStr);
    
    varStruct.audioDelay = audioDelay;
end

catch exception
    getReport(exception, 'extended', 'hyperlinks', 'on')
    rethrow(exception);
end

return;
% end of the function "interpretInputArguments"



%==========================================================================
% The function "getMatchingValue" verifies if any string in a given cell
% array of strings is among the odd-numbered entries of a specified cell
% vector, and if so the corresponding even-numbered entry is returned. The
% check is carried out in a case insensitive manner.
% INPUT: "testStrCellArr" is a cell array of strings to be searched for.
% "argInCellArr" is a cell vector whose odd-numbered cells are to be
% compared against the test strings while its even-numbered cells hold the
% corresponding values.
% OUTPUT: "value" returns the corresponding value if a matching cell is
% found, or an empty array ([]) otherwise.
% "testStr" returns the matching string if any is found, or an empty string
% ('') otherwise.
%==========================================================================
function [value, testStr] = getMatchingValue(testStrCellArr, argInCellArr)

for testStrInd = 1:numel(testStrCellArr)
    for k = 1:2:numel(argInCellArr)
        % If the given test string matches the current cell, then return the
        % content of the next cell.
        if (strcmpi(testStrCellArr{testStrInd}, argInCellArr{k}) == true)
            value = argInCellArr{k + 1};
            testStr = argInCellArr{k};
            return;
        end
    end
end

% If none of the given strings match any of the (odd-numbered) cells, then
% return an empty array ([]) and an empty string ('').
value = [];
testStr = '';

return;
% end of the function "getMatchingValue"


%==========================================================================
% The function "getBooleanValue" verifies if a given string is among the
% odd-numbered entries of a specified cell vector, and if so the
% corresponding even-numbered entry is returned provided it is a single
% boolean value. The check is carried out in a case insensitive manner.
% INPUT: "testStr" is a string to be searched for.
% "argInCellArr" is a cell vector whose odd-numbered cells are to be 
% compared against the test string while its even-numbered cells hold the
% corresponding values.
% OUTPUT: "value" returns the corresponding value if a matching cell is
% found, or an empty array ([]) otherwise.
%==========================================================================
function value = getBooleanValue(testStrCellArr, argInCellArr)

% Check if any of the test strings is among the specified input arguments,
% and if so get the corresponding value from the list of input arguments.
[value, testStr] = getMatchingValue(testStrCellArr, argInCellArr);
if ( ~isempty(value) )
    % Assert that the read value is boolean.
    assert(isa(value, 'logical'), 'SoundRestoration:getBooleanValue:NotTrueOrFalse', ...
        'The input argument immediately after %s is incompatible.\nIt must be boolean (true or false).', testStr);
else
    % Set a default value.
    value = false;
end

return;
% end of the function "getBooleanValue"
